package com.ss.web.tagmark.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.HtmlUtils;

import com.ss.web.tagmark.dao.AnnotationDao;
import com.ss.web.tagmark.dao.ArticleDao;
import com.ss.web.tagmark.dao.UserDao;
import com.ss.web.tagmark.entity.Annotation;
import com.ss.web.tagmark.entity.Article;
import com.ss.web.tagmark.entity.ArticleChar;
import com.ss.web.tagmark.entity.SystemParameter;
import com.ss.web.tagmark.entity.User;
import com.ss.web.tagmark.utils.AuthContext;

@Service
public class ArticleService extends BaseService<Article> {
	@Autowired
	private ArticleDao articleDao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private AnnotationDao annDao;
	@Autowired
	private ParameterService paramService;

	/**
	 * 获取指定id对应的文章信息
	 * 
	 * @param articleId
	 * @return
	 */
	public Article getById(Long articleId) {
		if (articleId == null) {
			return null;
		}
		return articleDao.getOne(articleId);
	}

	/**
	 * 获取指定文章的所有参与标注的用户
	 * 
	 * @param articleId
	 * @return
	 */
	public List<User> getUsersByArticleId(Long articleId) {
		if (articleId == null) {
			return null;
		}
		return userDao.selectByArticleId(articleId);
	}

	/**
	 * 将标注的信息保存起来
	 * 
	 * @param ann
	 * @return
	 */
	@Transactional
	public void markAnnotation(Annotation ann) {
		// 保存标注的信息，注意验证：选中的段落、词性要必填
		if (StringUtils.isBlank(ann.getSegment())) {
			return;
		}
		if (StringUtils.isBlank(ann.getPartOfSpeech())) {
			throw new IllegalArgumentException("请选择词性！");
		}
		if (ann.getArticleId() == null) {
			throw new IllegalArgumentException("数据不合法，没有指定属于哪个文章！");
		}
		// 处理offset，并将段落内容去无关的标志
		String s = ann.getSegment();
		Document doc = Jsoup.parse(s);
		Elements es = doc.getElementsByTag(ArticleChar.IDX_TAG);
		if (es.size() < 1) {
			throw new IllegalArgumentException("数据不合法，无法找到定位！");
		}
		String offset = es.get(0).attr("offset");
		if (!StringUtils.isNumeric(offset)) {
			throw new IllegalArgumentException("数据不合法，定位信息不正确！");
		}
		ann.setOffset(Integer.parseInt(offset));
		s = HtmlUtils.htmlUnescape(doc.text());
		ann.setSegment(s);
		// 验证是否已经存在
		synchronized (articleDao) {
			if (ann.getAnnotationId() == null) {// 新增的情况
				if (annDao.existsBySegmentAndOffsetAndOperId(ann.getSegment(), ann.getOffset(),
						AuthContext.getCurUser().getUserId())) {
					throw new IllegalArgumentException("该段文字已经被标注过！");
				}
				// 增加操作人信息
				ann.setOperId(AuthContext.getCurUser().getUserId());
				ann.setOperTime(new Date());
			}
			annDao.save(ann);
		}
	}

	/**
	 * 将文章中的内容处理成带有页面上无法显示的但每个字有序号的
	 * 
	 * @param article
	 * @return
	 */
	public String displayArticle(Long articleId, Long userId) {
		Article a = getById(articleId);
		if (a == null) {
			return "";
		}
		String s = StringUtils.defaultString(a.getContent());
		s = HtmlUtils.htmlEscape(s, "utf-8");
		List<ArticleChar> cs = new ArrayList<>();
		for (int i = 0; i < s.length(); i++) {
			ArticleChar ac = new ArticleChar();
			ac.setCh(s.charAt(i));
			ac.setIdx(i);
			cs.add(ac);
		}
		// 根据标注生成颜色信息
		List<Annotation> anns = getAnnotationsByArticleId(articleId, userId);
		if (anns != null) {
			for (Annotation ann : anns) {
				Integer start = ann.getOffset();
				if (start == null || start < 0 || start >= cs.size()) {
					continue;
				}
				ArticleChar ac = cs.get(start);
				ac.setExtra("<font color='" + ann.getColor() + "'>");// 加颜色
				ac = cs.get(start + ann.getSegment().length());
				ac.setExtra("</font>");// 颜色结尾
			}
		}
		StringBuilder result = new StringBuilder();
		for (ArticleChar ac : cs) {
			result.append(ac == null ? "" : ac.toString());
		}
		return result.toString();
	}

	/**
	 * 获取指定文章对应的所有的标注信息
	 * 
	 * @param articleId
	 * @return
	 */
	public List<Annotation> getAnnotationsByArticleId(Long articleId, Long userId) {
		return annDao.findByArticleIdAndOperId(articleId, userId);
	}

	/**
	 * 获取标注信息,同时将词性转换为名称
	 * 
	 * @param annId
	 * @return
	 */
	public Annotation getAnnotationById(Long annId) {
		if (annId == null) {
			return null;
		}
		Annotation ann = annDao.findById(annId).get();
		if (ann != null) {
			SystemParameter param = paramService.getByTypeAndValue(ParameterService.PART_OF_SPEECH,
					ann.getPartOfSpeech());
			if (param != null) {
				ann.setSpeechLabel(param.getLabel());
			}
		}
		return ann;
	}

	@Transactional
	public void deleteAnnById(Long annId) {
		annDao.deleteById(annId);
	}

}
